import os
import uuid
import shutil
import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import logging
from .file_parser import FileParser


class UploadManager:
    def __init__(self, base_upload_dir: str = "workspace/uploads"):
        self.base_upload_dir = base_upload_dir
        self.upload_sessions: Dict[str, Dict] = {}  # session_id -> 文件信息
        self.logger = logging.getLogger(__name__)
        self.file_parser = FileParser()  # 初始化文件解析器
        self._cleanup_old_files()
        self._load_existing_files()  # 加载已存在的文件

    def _cleanup_old_files(self):
        """清理24小时前的临时文件"""
        try:
            if not os.path.exists(self.base_upload_dir):
                return

            for session_dir in os.listdir(self.base_upload_dir):
                session_path = os.path.join(self.base_upload_dir, session_dir)
                if os.path.isdir(session_path):
                    stat = os.stat(session_path)
                    if datetime.now().timestamp() - stat.st_mtime > 24 * 3600:
                        shutil.rmtree(session_path)
                        if session_dir in self.upload_sessions:
                            del self.upload_sessions[session_dir]
                        self.logger.info(f"清理过期会话目录: {session_dir}")
        except Exception as e:
            self.logger.error(f"清理临时文件失败: {e}")

    def _load_existing_files(self):
        """系统启动时加载已存在的文件到内存中"""
        print("🔄 开始加载已存在的文件...")  # 添加调试信息
        try:
            if not os.path.exists(self.base_upload_dir):
                print("📁 上传目录不存在，跳过加载")
                return

            loaded_count = 0
            for session_dir in os.listdir(self.base_upload_dir):
                session_path = os.path.join(self.base_upload_dir, session_dir)
                if os.path.isdir(session_path):
                    session_id = session_dir
                    print(f"🔍 检查会话目录: {session_id}")
                    
                    # 初始化会话记录
                    if session_id not in self.upload_sessions:
                        self.upload_sessions[session_id] = {}
                    
                    # 先尝试加载元数据文件
                    metadata = self._load_metadata(session_id)
                    
                    # 扫描会话目录中的所有文件
                    for filename in os.listdir(session_path):
                        file_path = os.path.join(session_path, filename)
                        
                        # 跳过元数据文件
                        if filename == ".metadata.json":
                            continue
                            
                        if os.path.isfile(file_path):
                            try:
                                # 获取文件信息
                                stat = os.stat(file_path)
                                file_size = stat.st_size
                                
                                # 优先从元数据获取原始文件名和上传时间
                                if filename in metadata:
                                    original_name = metadata[filename]["original_name"]
                                    used = metadata[filename].get("used", True)
                                    upload_time = metadata[filename].get("upload_time", datetime.utcnow().isoformat() + "Z")
                                else:
                                    # 如果元数据中没有，则尝试推断
                                    original_name = self._guess_original_filename(filename, file_path)
                                    used = True
                                    # 对于没有元数据的旧文件，使用当前时间作为上传时间
                                    upload_time = datetime.utcnow().isoformat() + "Z"
                                
                                file_info = {
                                    "id": filename,
                                    "original_name": original_name,
                                    "saved_name": filename,
                                    "file_path": file_path,
                                    "size": file_size,
                                    "upload_time": upload_time,
                                    "used": used,  # 使用从元数据获取的状态
                                    "loaded_from_disk": True  # 标记为从磁盘加载
                                }
                                
                                self.upload_sessions[session_id][filename] = file_info
                                loaded_count += 1
                                
                                print(f"✅ 加载文件: {original_name} (会话: {session_id})")
                                
                            except Exception as e:
                                self.logger.warning(f"加载文件失败 {file_path}: {e}")
                                print(f"❌ 加载文件失败 {file_path}: {e}")
                                continue
            
            if loaded_count > 0:
                self.logger.info(f"系统启动时成功加载了 {loaded_count} 个已存在的文件")
                print(f"✅ 系统启动时成功加载了 {loaded_count} 个已存在的文件")  # 添加print确保能看到
            else:
                print("ℹ️ 系统启动时未发现需要加载的文件")
                
        except Exception as e:
            self.logger.error(f"加载已存在文件失败: {e}")
            print(f"❌ 加载已存在文件失败: {e}")

    def _guess_original_filename(self, saved_filename: str, file_path: str) -> str:
        """尝试推断原始文件名"""
        try:
            # 如果文件名包含UUID格式，尝试从文件内容或扩展名推断
            file_ext = os.path.splitext(saved_filename)[1]
            
            # 对于代码文件，尝试从内容推断功能
            if file_ext in ['.py', '.js', '.java', '.cpp', '.c', '.html', '.css']:
                try:
                    with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                        content = f.read(500)  # 只读前500字符
                        
                    # 简单的文件名推断逻辑
                    if 'fibonacci' in content.lower():
                        return f"fibonacci{file_ext}"
                    elif 'calculator' in content.lower():
                        return f"calculator{file_ext}"
                    elif 'sort' in content.lower():
                        return f"sorting{file_ext}"
                    elif 'class ' in content and file_ext == '.py':
                        return f"class_definition{file_ext}"
                    elif 'def ' in content and file_ext == '.py':
                        return f"functions{file_ext}"
                    else:
                        return f"code_file{file_ext}"
                        
                except:
                    pass
            
            # 默认使用文件类型作为名称
            if file_ext:
                return f"uploaded_file{file_ext}"
            else:
                return saved_filename
                
        except:
            return saved_filename

    def _get_metadata_file_path(self, session_id: str) -> str:
        """获取会话的元数据文件路径"""
        session_dir = self.get_session_upload_dir(session_id)
        return os.path.join(session_dir, ".metadata.json")

    def _save_metadata(self, session_id: str):
        """保存会话的元数据到文件"""
        try:
            metadata_path = self._get_metadata_file_path(session_id)
            metadata = {}
            
            if session_id in self.upload_sessions:
                for file_id, file_info in self.upload_sessions[session_id].items():
                    # 只保存必要的元数据信息
                    metadata[file_id] = {
                        "original_name": file_info.get("original_name", file_id),
                        "saved_name": file_info.get("saved_name", file_id),
                        "size": file_info.get("size", 0),
                        "upload_time": file_info.get("upload_time", ""),
                        "used": file_info.get("used", True)
                    }
            
            with open(metadata_path, 'w', encoding='utf-8') as f:
                json.dump(metadata, f, ensure_ascii=False, indent=2)
                
        except Exception as e:
            self.logger.warning(f"保存元数据失败: {e}")

    def _load_metadata(self, session_id: str) -> Dict:
        """从文件加载会话的元数据"""
        try:
            metadata_path = self._get_metadata_file_path(session_id)
            if os.path.exists(metadata_path):
                with open(metadata_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
        except Exception as e:
            self.logger.warning(f"加载元数据失败: {e}")
        return {}

    def get_session_upload_dir(self, session_id: str) -> str:
        """获取会话的上传目录"""
        # 防护措施：避免session_id与目录名冲突
        if session_id in ["uploads", "temp", "workspace", ".", "..", ""]:
            self.logger.warning(f"检测到可能导致路径冲突的session_id: {session_id}，使用默认值")
            session_id = "default"
        
        session_upload_dir = os.path.join(self.base_upload_dir, session_id)
        os.makedirs(session_upload_dir, exist_ok=True)
        return session_upload_dir

    def save_uploaded_file(self, session_id: str, filename: str, file_content: bytes) -> Dict:
        """保存上传的文件"""
        try:
            session_dir = self.get_session_upload_dir(session_id)

            # 生成唯一文件名避免冲突
            file_ext = os.path.splitext(filename)[1]
            unique_filename = f"{uuid.uuid4().hex}{file_ext}"
            file_path = os.path.join(session_dir, unique_filename)

            # 保存文件
            with open(file_path, "wb") as f:
                f.write(file_content)

            file_info = {
                "id": unique_filename,
                "original_name": filename,
                "saved_name": unique_filename,
                "file_path": file_path,
                "size": len(file_content),
                "upload_time": datetime.utcnow().isoformat() + "Z",
                "used": True  # False=不上传, True=要上传给LLM
            }

            # 保存到会话记录
            if session_id not in self.upload_sessions:
                self.upload_sessions[session_id] = {}

            self.upload_sessions[session_id][unique_filename] = file_info

            # 保存元数据到文件
            self._save_metadata(session_id)

            return file_info

        except Exception as e:
            self.logger.error(f"保存上传文件失败: {e}")
            raise

    def mark_file_for_use(self, session_id: str, file_id: str) -> bool:
        """标记文件为要使用（used=True）"""
        if (session_id in self.upload_sessions and
                file_id in self.upload_sessions[session_id]):
            self.upload_sessions[session_id][file_id]["used"] = True
            # 保存元数据
            self._save_metadata(session_id)
            return True
        return False

    def unmark_file_for_use(self, session_id: str, file_id: str) -> bool:
        """取消文件的使用标记（used=False）"""
        if (session_id in self.upload_sessions and
                file_id in self.upload_sessions[session_id]):
            self.upload_sessions[session_id][file_id]["used"] = False
            # 保存元数据
            self._save_metadata(session_id)
            return True
        return False

    def get_files_to_use(self, session_id: str) -> List[Dict]:
        """获取要使用的文件（used=True的）"""
        if session_id not in self.upload_sessions:
            return []

        return [
            file_info for file_info in self.upload_sessions[session_id].values()
            if file_info.get("used", False)
        ]

    def reset_used_files(self, session_id: str) -> bool:
        """重置所有文件的使用状态（used=False）"""
        if session_id in self.upload_sessions:
            for file_info in self.upload_sessions[session_id].values():
                file_info["used"] = False
            return True
        return False

    def read_file_content(self, session_id: str, file_id: str) -> Optional[str]:
        """读取文件内容 - 使用新的文件解析器"""
        file_info = self.get_file_info(session_id, file_id)
        if not file_info:
            return None

        try:
            # 使用文件解析器解析文件内容
            parse_result = self.file_parser.parse_file(
                file_info["file_path"], 
                file_info["original_name"]
            )
            
            if parse_result['success']:
                return parse_result['content']
            else:
                # 解析失败时返回错误信息
                return f"❌ 文件解析失败: {parse_result.get('error', '未知错误')}"
                
        except Exception as e:
            self.logger.error(f"读取文件失败: {e}")
            return f"❌ 读取文件时发生错误: {str(e)}"

    def get_file_info(self, session_id: str, file_id: str) -> Optional[Dict]:
        """获取文件信息"""
        if (session_id in self.upload_sessions and
                file_id in self.upload_sessions[session_id]):
            return self.upload_sessions[session_id][file_id]
        return None

    def get_session_files(self, session_id: str) -> List[Dict]:
        """获取会话的所有上传文件"""
        if session_id not in self.upload_sessions:
            return []
        return list(self.upload_sessions[session_id].values())

    def delete_file(self, session_id: str, file_id: str) -> bool:
        """删除上传的文件"""
        try:
            file_info = self.get_file_info(session_id, file_id)
            if not file_info:
                return False

            # 删除物理文件
            if os.path.exists(file_info["file_path"]):
                os.remove(file_info["file_path"])

            # 删除记录
            del self.upload_sessions[session_id][file_id]

            # 更新元数据文件
            if self.upload_sessions[session_id]:  # 如果会话还有其他文件
                self._save_metadata(session_id)

            # 清理空会话
            if not self.upload_sessions[session_id]:
                session_dir = self.get_session_upload_dir(session_id)
                if os.path.exists(session_dir):
                    shutil.rmtree(session_dir)
                del self.upload_sessions[session_id]

            return True

        except Exception as e:
            self.logger.error(f"删除文件失败: {e}")
            return False

    def clear_session_files(self, session_id: str) -> bool:
        """清空会话的所有上传文件"""
        try:
            if session_id not in self.upload_sessions:
                return True

            for file_id in list(self.upload_sessions[session_id].keys()):
                self.delete_file(session_id, file_id)

            return True

        except Exception as e:
            self.logger.error(f"清空会话文件失败: {e}")
            return False

    def _format_file_size(self, size_bytes: int) -> str:
        """格式化文件大小"""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        else:
            return f"{size_bytes / 1024 / 1024:.1f} MB"

    def get_supported_file_types(self) -> List[str]:
        """获取支持的文件类型列表"""
        return self.file_parser.get_supported_extensions()
    
    def is_file_supported(self, filename: str) -> bool:
        """检查文件是否支持解析"""
        return self.file_parser.is_supported(filename)
    
    def get_file_parse_info(self, session_id: str, file_id: str) -> Optional[Dict]:
        """获取文件解析信息（不实际解析内容，只返回解析状态信息）"""
        file_info = self.get_file_info(session_id, file_id)
        if not file_info:
            return None
        
        is_supported = self.is_file_supported(file_info["original_name"])
        file_ext = os.path.splitext(file_info["original_name"].lower())[1]
        
        return {
            "file_id": file_id,
            "original_name": file_info["original_name"],
            "file_extension": file_ext,
            "is_supported": is_supported,
            "file_size": file_info["size"],
            "formatted_size": self._format_file_size(file_info["size"]),
            "can_parse_content": is_supported
        }